package com.pj.compose.ui.page.widget

import androidx.compose.animation.core.MutableTransitionState
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.*
import androidx.compose.ui.window.Popup
import androidx.compose.ui.window.PopupPositionProvider
import androidx.compose.ui.window.PopupProperties
import androidx.navigation.NavController
import com.google.accompanist.flowlayout.FlowRow
import com.pj.compose.ui.compose.AppTopBarColumn

@Composable
fun PopupsPage(navController: NavController) {

    AppTopBarColumn(title = "Popups", backClick = { navController.popBackStack() }) {
        Box(modifier = Modifier.fillMaxSize()) {
            PopupButtons()

        }
    }
}

@Composable
private fun PopupButtons(onItemClick: (Int) -> Unit = {}) {
    val showPopups = remember {
        mutableStateListOf(false, false, false, false, false, false, false, false)
    }
    val items = listOf(
        "显示普通浮层",
        "显示列表浮层",
        "显示带遮罩的普通浮层",
        "显示浮层，并且动态更新内容",
        "全屏浮层，带关闭按钮",
        "全屏浮层，带输入",
        "快捷菜单",
        "快捷菜单（很多Item）"
    )
    val buttonColors = ButtonDefaults.buttonColors(
        containerColor = Color.White,
        contentColor = Color.White
    )
    val buttonBorder = BorderStroke(width = 1.dp, color = MaterialTheme.colorScheme.primary)
    FlowRow(Modifier.fillMaxSize()) {
        items.forEachIndexed { index, str ->
            Column {
                Button(
                    onClick = {
                        showPopups[index] = true
                        onItemClick(index)
                    },
                    modifier = Modifier
                        .padding(top = 15.dp)
                        .height(40.dp)
                        .padding(horizontal = 20.dp),
                    shape = RoundedCornerShape(20.dp),
                    border = buttonBorder,
                    colors = buttonColors
                ) {
                    Text(text = str, color = MaterialTheme.colorScheme.primary)
                }
                ButtonPopupWindow(showPopup = showPopups[index], onDismissRequest = {  showPopups[index] = false })
            }
        }
    }
}

@Composable
private fun ButtonPopupWindow(showPopup: Boolean = false, onDismissRequest: () -> Unit) {
    var arrowX by remember {
        mutableStateOf(50f)
    }
    DownPopup(
        expanded = showPopup,
        onDismissRequest = onDismissRequest,
        onPositionCalculated = { rect1, rect2 ->
//            "onPositionCalculated: $rect1 - $rect2".loge()
            arrowX = (rect1.right - rect1.left) / 2f + rect1.left - rect2.left
        }) {
        DownPopupContainer(
            modifier = Modifier.size(width = 300.dp, height = 100.dp),
            arrowX = arrowX,
        ){

        }
    }
}

@Composable
fun DownPopup(
    expanded: Boolean,
    onDismissRequest: () -> Unit,
    offset: DpOffset = DpOffset(5.dp, 0.dp),
    properties: PopupProperties = PopupProperties(focusable = true),
    onPositionCalculated: (IntRect, IntRect) -> Unit = { _, _ -> },
    content: @Composable () -> Unit
) {
    val expandedStates = remember { MutableTransitionState(false) }
    expandedStates.targetState = expanded

    if (expandedStates.currentState || expandedStates.targetState) {
        val density = LocalDensity.current
        val popupPositionProvider = DownMenuPositionProvider(
            offset,
            density,
            onPositionCalculated
        )

        Popup(
            onDismissRequest = onDismissRequest,
            popupPositionProvider = popupPositionProvider,
            properties = properties,
            content = content
        )
    }
}


private data class DownMenuPositionProvider(
    val contentOffset: DpOffset,
    val density: Density,
    val onPositionCalculated: (IntRect, IntRect) -> Unit = { _, _ -> }
) : PopupPositionProvider {
    override fun calculatePosition(
        anchorBounds: IntRect,
        windowSize: IntSize,
        layoutDirection: LayoutDirection,
        popupContentSize: IntSize
    ): IntOffset {
        // The min margin above and below the menu, relative to the screen.
        val verticalMargin = 0
        // The content offset specified using the dropdown offset parameter.
        val contentOffsetX = with(density) { contentOffset.x.roundToPx() }
        val contentOffsetY = with(density) { contentOffset.y.roundToPx() }

        // Compute horizontal position.
        val toRight = anchorBounds.left + contentOffsetX
        val toLeft = anchorBounds.right - contentOffsetX - popupContentSize.width
        val toDisplayRight = windowSize.width - popupContentSize.width
        val toDisplayLeft = 0
        val x = if (layoutDirection == LayoutDirection.Ltr) {
            sequenceOf(
                toRight,
                toLeft,
                // If the anchor gets outside of the window on the left, we want to position
                // toDisplayLeft for proximity to the anchor. Otherwise, toDisplayRight.
                if (anchorBounds.left >= 0) toDisplayRight else toDisplayLeft
            )
        } else {
            sequenceOf(
                toLeft,
                toRight,
                // If the anchor gets outside of the window on the right, we want to position
                // toDisplayRight for proximity to the anchor. Otherwise, toDisplayLeft.
                if (anchorBounds.right <= windowSize.width) toDisplayLeft else toDisplayRight
            )
        }.firstOrNull {
            it >= 0 && it + popupContentSize.width <= windowSize.width
        } ?: toLeft

        // Compute vertical position.
        val toBottom = maxOf(anchorBounds.bottom + contentOffsetY, verticalMargin)
        val toTop = anchorBounds.top - contentOffsetY - popupContentSize.height
        val toCenter = anchorBounds.top - popupContentSize.height / 2
        val toDisplayBottom = windowSize.height - popupContentSize.height - verticalMargin
        val y = sequenceOf(toBottom, toTop, toCenter, toDisplayBottom).firstOrNull {
            it >= verticalMargin &&
                    it + popupContentSize.height <= windowSize.height - verticalMargin
        } ?: toTop

        onPositionCalculated(
            anchorBounds,
            IntRect(x, y, x + popupContentSize.width, y + popupContentSize.height)
        )
        return IntOffset(x, y)
    }
}

@Composable
private fun DownPopupContainer(
    modifier: Modifier = Modifier,
    arrowX: Float = 50f,
    content: @Composable() (ColumnScope.() -> Unit)
) {
    Column(modifier = modifier.drawBehind {
        val path = Path()
//        path.moveTo(5.dp.toPx(), 10.dp.toPx())
        path.arcTo(
            Rect(center = Offset(5.dp.toPx(), 15.dp.toPx()), radius = 5.dp.toPx()),
            180f,
            90f,
            false
        )
//        绘制箭头
        path.lineTo(arrowX - 5.dp.toPx(), 10.dp.toPx())
        path.lineTo(arrowX, 0f)
        path.lineTo(arrowX + 5.dp.toPx(), 10.dp.toPx())

        path.lineTo(size.width - 5.dp.toPx(), 10.dp.toPx())
        path.arcTo(
            Rect(
                center = Offset(size.width - 5.dp.toPx(), 15.dp.toPx()),
                radius = 5.dp.toPx()
            ), -90f, 90f, false
        )
        path.lineTo(size.width, size.height - 5.dp.toPx())
        path.arcTo(
            Rect(
                center = Offset(size.width - 5.dp.toPx(), size.height - 5.dp.toPx()),
                radius = 5.dp.toPx()
            ), 0f, 90f, false
        )
        path.lineTo(5.dp.toPx(), size.height)
        path.arcTo(
            Rect(
                center = Offset(5.dp.toPx(), size.height - 5.dp.toPx()),
                radius = 5.dp.toPx()
            ), 90f, 90f, false
        )
//        path.lineTo(0f, 15.dp.toPx())

        path.close()
//        drawPath(path = path, color = Color.Black.copy(alpha = 0.2f), alpha = 1f, style = Stroke(1.dp.toPx()))
        drawPath(path = path, color = Color.Black.copy(alpha = 0.3f), alpha = 1f)
    }, content = content)
}